`include "src/alu_ctrl.v"
`include "src/alu.v"
`include "src/ctrl.v"
`include "src/data_mem.v"
`include "src/imm_gen.v"
`include "src/instr_mem.v"
`include "src/next_pc.v"
`include "src/pc_reg.v"
`include "src/reg_files.v"

module cpu_top (
  input clk,
  input rst
);
  
  // Instruction Memory 输出
  wire [31:0] instr;
  wire [6:0]  opcode;
  wire [2:0]  func3;
  wire [6:0]  func7;
  wire [4:0]  rs1;
  wire [4:0]  rs2;
  wire [4:0]  rd;

  // Imm Gen 输出
  wire [31:0] imm;

  // Register Files 输出
  wire [31:0] rf_read_data1;
  wire [31:0] rf_read_data2;

  // ALU 输出
  wire alu_zero;
  wire [31:0] alu_result;

  // Control 输出
  wire branch;
  wire mem_to_reg;
  wire [1:0] alu_op;
  wire mem_write;
  wire alu_src;
  wire reg_write;
  wire [2:0] imm_ctrl;
  // ALU Control 输出
  wire [3:0] alu_op_ctrl;

  // Data Memory 输出
  wire [31:0] dm_read_data;

  // PC 输出
  wire [31:0] pc;
  // Next PC 输出
  wire [31:0] next_pc;

  // Mux 单元产生的补充
  wire[31:0] rf_write_data;
  wire[31:0] alu_input_2;

  assign alu_input_2 = (alu_src == 0) ? rf_read_data2 : imm;
  assign rf_write_data = (mem_to_reg == 0) ? alu_result : dm_read_data;

  assign opcode = instr[6:0];
  assign func3  = instr[14:12];
  assign func7  = instr[31:25];
  assign rs1    = instr[19:15];
  assign rs2    = instr[24:20];
  assign rd     = instr[11:7];

  pc_reg U_PC(
    .clk(clk),
    .rst(rst),
    .next_pc(next_pc),
    .pc(pc)
  );

  instr_mem U_INSTR_MEM(
    .addr(pc),
    .instr(instr)
  );

  reg_files U_REG_FILES(
    .clk(clk),
    .rst(rst),
    .reg_write(reg_write),
    .rs1(rs1),
    .rs2(rs2),
    .rd(rd),
    .write_data(rf_write_data),
    .read_data1(rf_read_data1),
    .read_data2(rf_read_data2)
  );

  imm_gen U_IMM_GEN(
    .instr(instr),
    .imm_ctrl(imm_ctrl),
    .imm(imm)
  );

  ctrl U_CTRL(
    .instr(instr),
    .branch(branch),
    .mem_to_reg(mem_to_reg),
    .alu_op(alu_op),
    .mem_write(mem_write),
    .alu_src(alu_src),
    .reg_write(reg_write),
    .imm_ctrl(imm_ctrl)
  );

  alu_ctrl U_ALU_CTRL(
    .alu_op(alu_op),
    .func3(func3),
    .func7(func7),
    .alu_op_ctrl(alu_op_ctrl)
  );

  alu U_ALU(
    .alu_in1(rf_read_data1),
    .alu_in2(alu_input_2),
    .alu_op_ctrl(alu_op_ctrl),
    .alu_result(alu_result),
    .zero(alu_zero)
  );

  data_mem U_DATA_MEM(
    .clk(clk),
    .rst(rst),
    .mem_write(mem_write),
    .addr(alu_result),
    .write_data(rf_read_data2),
    .read_data(dm_read_data)
  );

  next_pc U_NEXT_PC(branch, alu_zero, imm, pc, next_pc);

endmodule